/**
 * 
 */
package org.istt.web;

import java.text.ParseException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import javax.servlet.ServletContext;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.apache.commons.lang.time.DateUtils;
import org.apache.struts2.ServletActionContext;
import org.istt.domain.Category;
import org.istt.domain.Department;
import org.istt.domain.Exchange;
import org.istt.domain.Field;
import org.istt.domain.File;
import org.istt.domain.Group;
import org.istt.domain.SubCategory;
import org.istt.domain.User;
import org.istt.model.DepartmentReportView;
import org.istt.model.FileBean;
import org.istt.model.FileReportBean;
import org.istt.model.GeneralReportBean;
import org.istt.service.CategoryManager;
import org.istt.service.DepartmentManager;
import org.istt.service.ExchangeManager;
import org.istt.service.FieldManager;
import org.istt.service.FileManager;
import org.istt.service.GroupManager;
import org.istt.service.TimeHolidayManager;
import org.istt.service.TimeWeekendManager;
import org.istt.service.UserManager;
import org.istt.web.helper.ExtendedPaginatedList;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;

import com.opensymphony.xwork2.ActionContext;

/**
 * @author NDTHO
 * 
 */
public class StatisticsAction extends BaseAction<FileManager, File, String> {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	private static Object resizeArray (Object oldArray, int newSize) {
		   int oldSize = java.lang.reflect.Array.getLength(oldArray);
		   Class elementType = oldArray.getClass().getComponentType();
		   Object newArray = java.lang.reflect.Array.newInstance(
		         elementType,newSize);
		   int preserveLength = Math.min(oldSize,newSize);
		   if (preserveLength > 0)
		      System.arraycopy (oldArray,0,newArray,0,preserveLength);
		   return newArray; }
	
	private CategoryManager categoryManager;
	private String departmentId;
	private String cateId;
	public String getCateId() {
		return cateId;
	}

	public void setCateId(String cateId) {
		this.cateId = cateId;
	}

	private DepartmentManager departmentManager;
	private List<Department> departments;
	private String fieldId;
	private FieldManager fieldManager;
	private ExtendedPaginatedList fileList;
	
	private FileManager fileManager;
	private int fileReceivedThisMonth=0;
	private int fileRemainLastMonth=0;
	private List<FileReportBean> files;
	private List<Object[]> files2;
	/**
	 * 
	 */

	private String fromDate;
	private String groupId;
	private GroupManager groupMgr;
	
	private TimeHolidayManager holidayManager;
	private List<Object[]> nameIdProcessStatus;
	private String reportOnTime;
	private String reportOverTime;
	private List<GeneralReportBean> reports;
	private String reportType;
	private ExtendedPaginatedList resultFileByUser;
	private ExtendedPaginatedList lstFileByDepartment;
	private String select_notapprove;
	private String select_overtime;
	private String selectedType;
	private String statistic;
	private String toDate;
	private int totalFileOvertime;
	private int totalFiles;
	private String userId;
	
	
	
	private UserManager userManager;
	
	private TimeWeekendManager weekendManager;

	/**
	 * START_DATE =< APPROVED_DATE <= END_DATE
	 * @param file
	 * @param startDate
	 * @param endDate
	 * @return
	 */
	private boolean checkApprovedFiles(File file,Date startDate, Date endDate){
		if(file.getDateCompleted()!=null){
			log.debug("------------COMPLETED DATE: "+file.getDateCompleted().toString());
			Calendar tmpEndDate = Calendar.getInstance();
			tmpEndDate.setTime(endDate);
			tmpEndDate.set(tmpEndDate.get(Calendar.YEAR), tmpEndDate.get(Calendar.MONTH), tmpEndDate.get(Calendar.DAY_OF_MONTH), 23, 59);
			Date completedDate = file.getDateCompleted().toDate();
			if(completedDate.after(startDate) && completedDate.before(tmpEndDate.getTime())) return true;
			else return false;
		}
		
		return false;
	}
	
	public List<NameValuePair> getCategories() {
		List<NameValuePair> catList = new ArrayList<NameValuePair>();
		if (!StringUtils.isEmpty(departmentId)) {
			if (log.isDebugEnabled()) {
				log.debug("departmentId is equal to " + fieldId
						+ " getting categories");
			}

		List<Category> categories = categoryManager.getByDepartmentId(NumberUtils
					.toLong(departmentId));
			for (Category c : categories) {
				NameValuePair elm = new NameValuePair();
				elm.setName(c.getCategoryName());
				elm.setValue(c.getId() + "");
				catList.add(elm);
			}
		}
		return catList;
	}

	@Override
	public String execute() {
        if (statistic != null) {
            return "statistic";
        }
        if (reportOnTime != null) {
        	return "reportByDepartment";
        }
        if (reportOverTime != null) {
        	return "reportOverTime";
        }
        
        return SUCCESS;
    }
	
	public CategoryManager getCategoryManager() {
		return categoryManager;
	}

	public String getDepartmentId() {
		return departmentId;
	}

	public DepartmentManager getDepartmentManager() {
		return departmentManager;
	}

	public List<Department> getDepartments() {
		List<Department> deptLst = new ArrayList<Department>();
		Department dept = new Department();
		dept.setName(getText("reportByDepartment.form.reportall"));
		dept.setId(new Long(0));
		deptLst.add(dept);
		if(departmentManager.getList().size()!=0){
			List<Department> lst = departmentManager.getList();
			for (Iterator<Department> iterator = lst.iterator(); iterator.hasNext();) {
				Department department = (Department) iterator.next();
				deptLst.add(department);
			}
		}
		
		return deptLst;
	}	
	
	/**
	 * Tinh toan va tra ve ket qua xu ly ho so. Cho biet thong tin xu ly ho so:
	 * - Dung han
	 * - Qua han
	 * - Con han
	 * ...
	 * @param objFile
	 * @param fromDate
	 * @param toDate
	 * @param weekends
	 * @param holidays
	 * @return
	 */
	private FileBean getResultOfFile(File file, Date fromDate, Date toDate, List<Integer> weekends,List<Date> holidays){
		FileBean result = null;
		int processTime = 0;
		Date receivedDate = file.getInputDate().toDate();
		Date outputDate = file.getOutputDate().toDate();
		String categoryName = file.getCategory().getCategoryName();
		
		DateTime completedDate = file.getDateCompleted();
		
		//Tinh toan thoi gian xu ly ho so theo ngay hen tra
		processTime = getWorkingDays(receivedDate, outputDate,weekends,holidays);
		
		// Cap nhat Ho ten nguoi tiep nhan ho so
		User createdBy = userManager.get(file.getCreatedBy().getId());
		file.setCreatedBy(createdBy);
		
		// CASE 1: HO SO XU LY XONG
		if(completedDate!=null && receivedDate!=null){
			
			// Tinh toan thoi gian thuc xu ly ho so, tinh den ngay xu ly xong
			int realTime = getWorkingDays(receivedDate, completedDate.toDate(), weekends, holidays);
			
			// Thoi gian chenh lech giua Ngay hen va Ngay thuc te
			int overtime = realTime - processTime;
			
			// Xu ly dung han
			if(realTime == processTime || realTime < processTime){
				
				result = new FileBean(file,getText("reportByDepartment.excel.table.content.DH"),getText("reportByDepartment.excel.table.content.note.DH"),categoryName);
								
			}
			// Xu ly qua han
			else if(realTime > processTime){
					String processResult = "";
					String noteResult = "";
					
					if(overtime <= WebConstants.FIVE){
						processResult = getText("reportByDepartment.excel.table.content.T5");
						noteResult = getText("reportByDepartment.excel.table.content.note.QH");
					}
					else if(overtime > WebConstants.FIVE && overtime <=WebConstants.TEN){
						processResult = getText("reportByDepartment.excel.table.content.T10");
						noteResult = getText("reportByDepartment.excel.table.content.note.QH");
					}
					else if(overtime > WebConstants.TEN && overtime <=WebConstants.TWENTY){
						processResult = getText("reportByDepartment.excel.table.content.T20");
						noteResult = getText("reportByDepartment.excel.table.content.note.QH");
					}
					else if(overtime > WebConstants.TWENTY ){
						processResult = getText("reportByDepartment.excel.table.content.T30");
						noteResult = getText("reportByDepartment.excel.table.content.note.QH");
					}
					
				result = new FileBean(file, processResult, noteResult, categoryName);
			}
		}
		// CASE 2: Ho so chua xu ly xong
		else if(completedDate == null){
			int realTime = getWorkingDays(receivedDate, toDate, weekends, holidays);
			
			if(processTime <= realTime){
				
				result = new FileBean(file,getText("reportByDepartment.excel.table.content.QH"),getText("reportByDepartment.excel.table.content.note.QH"),categoryName);
				
			}else 
				if(processTime > realTime){
					result = new FileBean(file,getText("reportByDepartment.excel.table.content.CH"),getText("reportByDepartment.excel.table.content.note.CH"),categoryName);
			}
		}
		
		return result;
	}
	
	private void getFileForDeptReport(List<File> lstFile,Date t,Date f,List<Integer> weekends,List<Date> holidays,FileReportBean result, String categoryName){
		for (File file : lstFile) {
			int processTime = 0;
//			log.debug("CHECKING FILE: "+file.getContactName());
			Date receivedDate = file.getInputDate().toDate();
			DateTime approvedDate = file.getDateCompleted();
			
			//Calculate process time
			processTime = getWorkingDays(file.getInputDate().toDate(), file.getOutputDate().toDate(),weekends,holidays);
			
//			log.debug("------------PROCESS TIME: "+processTime);
			if(reportType!=null && reportType.equals(WebConstants.REPORT_TYPE_PROCESS_OVER_TIME)){
				if(checkApprovedFiles(file, f, t)){
					
					//Update number of files that approved on time
					if(approvedDate!=null && receivedDate!=null){
						//REAL_TIME = (APPROVED_DATE � RECEIVED_DATE) � HOLIDAY � WEEKEND
						int realTime = getWorkingDays(receivedDate, approvedDate.toDate(),weekends,holidays);
//						int realTime = (int)( (approvedDate.toDate().getTime() - receivedDate.getTime()) / (1000 * 60 * 60 * 24));
						log.debug("------------REALTIME: "+realTime);
						
						User createdBy = userManager.get(file.getCreatedBy().getId());
						file.setCreatedBy(createdBy);
						int overtime = realTime - processTime;
						
						//TODO: Report files that are completed on time
						if(select_overtime.equals(WebConstants.OVER_TIME_ONTIME) && (realTime == processTime || realTime < processTime)){
							
							FileBean fileReport = new FileBean(file,getText("reportByDepartment.excel.table.content.DH"),getText("reportByDepartment.excel.table.content.note.DH"),categoryName);
							result.addFile(fileReport);
							
						}else //TODO: Report files that are completed over deadline 
							if(select_overtime.equals(WebConstants.OVER_TIME_OVERTIME) && (realTime > processTime)){
								//TODO: update overtime
								String processResult = "";
								String noteResult = "";
								
								if(overtime <= WebConstants.FIVE){
									processResult = getText("reportByDepartment.excel.table.content.T5");
									noteResult = getText("reportByDepartment.excel.table.content.note.QH");
								}
								else if(overtime > WebConstants.FIVE && overtime <=WebConstants.TEN){
									processResult = getText("reportByDepartment.excel.table.content.T10");
									noteResult = getText("reportByDepartment.excel.table.content.note.QH");
								}
								else if(overtime > WebConstants.TEN && overtime <=WebConstants.TWENTY){
									processResult = getText("reportByDepartment.excel.table.content.T20");
									noteResult = getText("reportByDepartment.excel.table.content.note.QH");
								}
								else if(overtime > WebConstants.TWENTY ){
									processResult = getText("reportByDepartment.excel.table.content.T30");
									noteResult = getText("reportByDepartment.excel.table.content.note.QH");
								}
								
								log.debug("------------ADD FOUND FILE TO LIST: "+file.getContactName());
								FileBean fileReport = new FileBean(file,processResult,noteResult,categoryName);
								result.addFile(fileReport);	
						}else if(select_overtime.equals(WebConstants.OVER_TIME_OVERTIME_T5) && (realTime > processTime)){
							
							
							if(overtime <= WebConstants.FIVE){
								FileBean fileReport = new FileBean(file,getText("reportByDepartment.excel.table.content.T5"),getText("reportByDepartment.excel.table.content.note.QH"),categoryName);
								result.addFile(fileReport);	
							}
						}else if(select_overtime.equals(WebConstants.OVER_TIME_OVERTIME_T510) && (realTime > processTime)){
							if(overtime > WebConstants.FIVE && overtime <=WebConstants.TEN){
								FileBean fileReport = new FileBean(file,getText("reportByDepartment.excel.table.content.T10"),getText("reportByDepartment.excel.table.content.note.QH"),categoryName);
								result.addFile(fileReport);	
							}
						}else if(select_overtime.equals(WebConstants.OVER_TIME_OVERTIME_T1020) && (realTime > processTime)){
							if(overtime > WebConstants.TEN && overtime <=WebConstants.TWENTY){
								FileBean fileReport = new FileBean(file,getText("reportByDepartment.excel.table.content.T20"),getText("reportByDepartment.excel.table.content.note.QH"),categoryName);
								result.addFile(fileReport);	
							}
						}else if(select_overtime.equals(WebConstants.OVER_TIME_OVERTIME_T20) && (realTime > processTime)){
							if(overtime > WebConstants.TWENTY){
								FileBean fileReport = new FileBean(file,getText("reportByDepartment.excel.table.content.T30"),getText("reportByDepartment.excel.table.content.note.QH"),categoryName);
								result.addFile(fileReport);	
							}
						}
					}else{
						log.debug("------------INPUT DATE & COMPLETED DATE IS NULL");
					}
				}
			}
			// LIST ALL FILES THAT HAVE NOT APPROVED
			else if(reportType!=null && reportType.equals(WebConstants.REPORT_TYPE_PROCESS_NOT_APPROVED)){
				if(approvedDate == null){
//					int realTime = (int)( (t.getTime() - receivedDate.getTime()) / (1000 * 60 * 60 * 24));
					int realTime = getWorkingDays(receivedDate, t,weekends,holidays);
					log.debug("------------REALTIME: "+realTime +" PROCESS TIME: "+processTime);
					//TODO: report files that have not yet completed and expire
					User createdBy = userManager.get(file.getCreatedBy().getId());
					file.setCreatedBy(createdBy);
					if(select_notapprove.equals(WebConstants.NOT_APPROVED_TYPE_EXPIRATION) && (processTime <= realTime)){
						FileBean fileReport = new FileBean(file,getText("reportByDepartment.excel.table.content.QH"),getText("reportByDepartment.excel.table.content.note.QH"),categoryName);
						result.addFile(fileReport);	
					}else //TODO: report files that have not yet completed but not expiration
						if(select_notapprove.equals(WebConstants.NOT_APPROVED_TYPE_NOTEXPIRATION) && (processTime > realTime)){
							FileBean fileReport = new FileBean(file,getText("reportByDepartment.excel.table.content.CH"),getText("reportByDepartment.excel.table.content.note.CH"),categoryName);
							result.addFile(fileReport);										
					}
				}
			}
		}
	}
	
	/***
	 * Calculate value of field according to Algorithm 
	 * @param deptname the name of department
	 * @param categories the list of category
	 * @param t the start point to statistic 
	 * @param f the end point to statistic
	 * @return <code>FileReportBean</code>
	 */
	private FileReportBean getDeptReport(String deptname, Set<Category> categories,Date t,Date f,List<Integer> weekends,List<Date> holidays){

		FileReportBean result = new FileReportBean(deptname);
		for (Iterator<Category> iterator = categories.iterator(); iterator.hasNext();) {
			Category category = iterator.next();
			
			if(category.getSubCategories().size()!=0){
				Set<SubCategory> lstSubCate = category.getSubCategories(); 
				for (Iterator<SubCategory> iterator2 = lstSubCate.iterator(); iterator2.hasNext();) {
					SubCategory subCategory = (SubCategory) iterator2.next();
					List<File> lstFile = fileManager.getFilesForReport(category.getId(),subCategory.getId(), f, t);
				
					getFileForDeptReport(lstFile, t, f, weekends, holidays, result,category.getCategoryName() + "("+subCategory.getName()+ ")");
				}
				
			}else{
				List<File> lstFile = fileManager.getFilesForReport(category.getId(),null, f, t);
				
				getFileForDeptReport(lstFile, t, f, weekends, holidays, result,category.getCategoryName());
			}
		}
		
		return result;
	
	}
	public String getFieldId() {
		return fieldId;
	}
	
	public List<Field> getFields() {
		return fieldManager.getList();
	}
	
	public ExtendedPaginatedList getFileList() {
		return fileList;
	}

	public FileManager getFileManager() {
		return fileManager;
	}
	
	public int getFileReceivedThisMonth() {
		return fileReceivedThisMonth;
	}
	
	
	public int getFileRemainLastMonth() {
		return fileRemainLastMonth;
	}
	
	public List<FileReportBean> getFiles() {
		return files;
	}
	public List<Object[]> getFiles2() {
		return files2;
	}
	
	/**
	 * @return the fromDate
	 */
	public String getFromDate() {
		return fromDate;
	}
	
	public String getGroupId() {
		return groupId;
	}

	public TimeHolidayManager getHolidayManager() {
		return holidayManager;
	}

	@Override
	public String getId() {
		return null;
	}

	
	public List<Group> getListGroup() {
		List<Group> lstGroup = new ArrayList<Group>();
		lstGroup = groupMgr.getList();
		return lstGroup;
	}

	public List<NameValuePair> getListUser() {
		List<NameValuePair> lstUser = new ArrayList<NameValuePair>();
		if (!StringUtils.isEmpty(groupId)) {
			if (log.isDebugEnabled()) {
				log.debug("groupId is equal to " + groupId + " getting users");
			}
			List<User> lstUsers = new ArrayList<User>();
			lstUsers = userManager.findUserByDeptId(NumberUtils.toLong(groupId));
			for (User u : lstUsers) {
				NameValuePair elm = new NameValuePair();
				elm.setName(u.getFullname());
				elm.setValue(u.getId() + "");
				lstUser.add(elm);
			}
		}
		return lstUser;
	}

	public List<Department> getLstDepartments() {
		return departmentManager.getList();
	}

	public List<Object[]> getNameIdProcessStatus() {
		return nameIdProcessStatus;
	}

	public String getReportOnTime() {
		return reportOnTime;
	}

	public String getReportOverTime() {
		return reportOverTime;
	}

	public List<GeneralReportBean> getReports() {
		return reports;
	}

	public String getReportType() {
		return reportType;
	}

	public ExtendedPaginatedList getResultFileByUser() {
		return resultFileByUser;
	}
	
	public String getSelect_notapprove() {
		return select_notapprove;
	}

	public String getSelect_overtime() {
		return select_overtime;
	}

	public String getSelectedType() {
		return selectedType;
	}
	
	public String getStatistic() {
		return statistic;
	}

	public String getToDate() {
		return toDate;
	}
	
	public int getTotalFileOvertime() {
		return totalFileOvertime;
	}

	public int getTotalFiles() {
		return totalFiles;
	}

	public String getUserId() {
		return userId;
	}

	public TimeWeekendManager getWeekendManager() {
		return weekendManager;
	}

	/***
	 * Calculate number of working day between two dates without weekend
	 * @param startDt
	 * @param endDt
	 * @return number of working day
	 */
	public int getWorkingDays(Date startDt, Date endDt, List<Integer> weekend,List<Date> holiday) {
		Calendar startCal, endCal;
		startCal = Calendar.getInstance();
		startCal.setTime(startDt);
		endCal = Calendar.getInstance();
		endCal.setTime(endDt);
		int workDays = 0;

		// Return 0 if start and end are the same
		if (startCal.getTimeInMillis() == endCal.getTimeInMillis()) {
			return 0;
		}
		// Just in case the dates were transposed this prevents infinite loop
		if (startCal.getTimeInMillis() > endCal.getTimeInMillis()) {
			startCal.setTime(endDt);
			endCal.setTime(startDt);
		}

		do {
			startCal.add(Calendar.DAY_OF_MONTH, 1);
			if (isNotWeekend(startCal,weekend) && isNotHoliday(startCal, holiday)) {
//				System.err.println("====>> WORKING DAY: "+startCal.get(Calendar.DATE)+"/"+startCal.get(Calendar.MONTH)+"/"+startCal.get(Calendar.YEAR));
				++workDays;
			}
		} while (startCal.getTimeInMillis() < endCal.getTimeInMillis());

		return workDays;
	}

	private boolean isNotHoliday(Calendar inputDate, List<Date> holidays){
		
		for (int i = 0; i < holidays.size(); i++) {
			Calendar holiday = Calendar.getInstance();
			holiday.setTime(holidays.get(i));
			if (inputDate.get(Calendar.YEAR) == holiday.get(Calendar.YEAR) && 
					inputDate.get(Calendar.MONTH) == holiday.get(Calendar.MONTH) && 
					inputDate.get(Calendar.DAY_OF_MONTH) == holiday.get(Calendar.DAY_OF_MONTH)){
				return false;
			}
		}
	return true;
}

	private boolean isNotWeekend(Calendar inputDate, List<Integer> weekend){
		int dayOfWeek = inputDate.get(Calendar.DAY_OF_WEEK);
		for (int i = 0; i < weekend.size(); i++) {
			if (dayOfWeek == weekend.get(i).intValue()){
				return false;
			}
		}
		return true;
	}

	@Override
    public  String list() {
    	if (log.isDebugEnabled()) {
            log.debug("entering 'list' method");
        }
        return SUCCESS; 
    }

	/***
	 * Generate report of all departments or one department
	 * @return
	 * @throws Exception
	 */
	public String reportByDepartment() throws Exception {
		Long startPoint = System.currentTimeMillis();
		files = new ArrayList<FileReportBean>();
		
		if (log.isDebugEnabled()) {
			log.debug("entering 'reportFilesOnTime' method");
		}
		
		// Field counter, auto increment
		int fieldCount =0;
		
		if(fromDate!=null && !"".equals(fromDate) && toDate!=null && !"".equals(toDate)){
			Date f = StringUtils.isEmpty(fromDate) ? null : DateUtils.parseDate(
					fromDate, new String[] { getText("date.format") });
			Date t = StringUtils.isEmpty(toDate) ? null : DateUtils.parseDate(
					toDate, new String[] { getText("date.format") });
			
			log.debug("------------ENTERING REPORT------------");
			log.debug("------------START_DATE: "+f.toString());
			log.debug("GET REPORT TYPE = "+reportType);
			
			List<Field> fields = fieldManager.getList();
			ServletContext servletContext = ServletActionContext.getServletContext();
			
			List<Integer> weekends = weekendManager.getWeekend();
			List<Date> holidays = holidayManager.getHolidays(f,t);
			
			if(this.departmentId!=null && !"".equals(this.departmentId)){
				for (fieldCount = 0; fieldCount < fields.size(); fieldCount++) {
					Field field = fields.get(fieldCount);
					
					//Report for all department
					if(this.departmentId.equals("0")){
						
						Set<Category> categories = field.getCategories();
						
						FileReportBean fileReport = getDeptReport(field.getDepartment().getName(),categories,t,f,weekends,holidays);
						
						if(fileReport.getLstFile().size()!=0) this.files.add(fileReport);
						
					}else if(field.getDepartment().getId().equals(Long.parseLong(this.departmentId))){
						
						Set<Category> categories = null;
						
						if(StringUtils.isNotEmpty(this.cateId) && !this.cateId.equals("0")){
							Category selectedCategory = categoryManager.get(Long.parseLong(this.cateId));
							categories = new HashSet<Category>();
							if(selectedCategory != null) categories.add(selectedCategory);
								
						}else{
							categories = field.getCategories();	
						}
						
						FileReportBean fileReport = getDeptReport(field.getDepartment().getName(),categories,t,f,weekends,holidays);
						
						if(fileReport.getLstFile().size()!=0) this.files.add(fileReport);
					}
				}
			}
			log.debug("TOTAL FILES: "+this.files.size());
			servletContext.setAttribute(WebConstants.SERVLET_CONTEXT_REPORT, this.files);
			servletContext.setAttribute(WebConstants.REPORT_TYPE, reportType);
			servletContext.setAttribute(WebConstants.SERVLET_CONTEXT_FROMDATE, this.fromDate);
			servletContext.setAttribute(WebConstants.SERVLET_CONTEXT_TODATE, this.toDate);
			
		}else{
			return SUCCESS;
		}
		
		Long endPoint = System.currentTimeMillis();
		log.debug("------------TIME TO GENERATE REPORT: "+(endPoint-startPoint));
		return SUCCESS;
	}

	@Autowired
	public void setCategoryManager(CategoryManager categoryManager) {
		this.categoryManager = categoryManager;
	}

	@Override
	protected void setDeleteMessage() {
		ActionContext.getContext().getSession()
				.put("message", getText("file.deleted"));
	}

	public void setDepartmentId(String departmentId) {
		this.departmentId = departmentId;
	}

	@Autowired
	public void setDepartmentManager(DepartmentManager departmentManager) {
		this.departmentManager = departmentManager;
	}

	public void setDepartments(List<Department> departments) {
		this.departments = departments;
	}

	public void setFieldId(String fieldId) {
		this.fieldId = fieldId;
	}

	public void setFieldManager(FieldManager fieldManager) {
		this.fieldManager = fieldManager;
	}

	public void setFileList(ExtendedPaginatedList fileList) {
		this.fileList = fileList;
	}

	@Autowired
	public void setFileManager(FileManager fileManager) {
		this.fileManager = fileManager;
	}

	public void setFileReceivedThisMonth(int fileReceivedThisMonth) {
		this.fileReceivedThisMonth = fileReceivedThisMonth;
	}

	public void setFileRemainLastMonth(int fileRemainLastMonth) {
		this.fileRemainLastMonth = fileRemainLastMonth;
	}

	public void setFiles(List<FileReportBean> files) {
		this.files = files;
	}

	public void setFiles2(List<Object[]> files2) {
		this.files2 = files2;
	}

	/**
	 * @param fromDate
	 *            the fromDate to set
	 */
	public void setFromDate(String fromDate) {
		this.fromDate = fromDate;
	}

	public void setGroupId(String groupId) {
		this.groupId = groupId;
	}

	public void setGroupMgr(GroupManager groupMgr) {
		this.groupMgr = groupMgr;
	}

	@Autowired
	public void setHolidayManager(TimeHolidayManager holidayManager) {
		this.holidayManager = holidayManager;
	}
	
	public void setNameIdProcessStatus(List<Object[]> nameIdProcessStatus) {
		this.nameIdProcessStatus = nameIdProcessStatus;
	}
	
	public void setReportOnTime(String reportOnTime) {
		this.reportOnTime = reportOnTime;
	}

	public void setReportOverTime(String reportOverTime) {
		this.reportOverTime = reportOverTime;
	}

	public void setReports(List<GeneralReportBean> reports) {
		this.reports = reports;
	}

	public void setReportType(String reportType) {
		this.reportType = reportType;
	}
	public void setResultFileByUser(ExtendedPaginatedList resultFileByUser) {
		this.resultFileByUser = resultFileByUser;
	}

	@Override
	protected void setSaveMessage() {
		ActionContext.getContext().getSession()
				.put("message", getText("file.saved"));
	}

	public void setSelect_notapprove(String select_notapprove) {
		this.select_notapprove = select_notapprove;
	}
	public void setSelect_overtime(String select_overtime) {
		this.select_overtime = select_overtime;
	}

	public void setSelectedType(String selectedType) {
		this.selectedType = selectedType;
	}

	public void setStatistic(String statistic) {
		this.statistic = statistic;
	}

	public void setToDate(String toDate) {
		this.toDate = toDate;
	}

	public void setTotalFileOvertime(int totalFileOvertime) {
		this.totalFileOvertime = totalFileOvertime;
	}

	public void setTotalFiles(int totalFiles) {
		this.totalFiles = totalFiles;
	}

	public void setUserId(String userId) {
		this.userId = userId;
	}

	public void setUserManager(UserManager userManager) {
		this.userManager = userManager;
	}


	@Autowired
	public void setWeekendManager(TimeWeekendManager weekendManager) {
		this.weekendManager = weekendManager;
	}

	/***
	 * NDTHO
	 */
	public String calculateSynthesisReport() throws Exception {
		Long startPoint = System.currentTimeMillis();
		reports = new ArrayList<GeneralReportBean>();
		fileRemainLastMonth = 0;
		fileReceivedThisMonth = 0;
		
		if (log.isDebugEnabled()) {
			log.debug("------------ENTERING REPORT------------");
		}
		
		// Field counter, auto increment
		int fieldCount =0;
		// Category counter, auto increment
		int categoryCount =0;
		if(fromDate!=null && !"".equals(fromDate) && toDate!=null && !"".equals(toDate)){
			
			ServletContext servletContext = ServletActionContext.getServletContext();
			
			Date f = StringUtils.isEmpty(fromDate) ? null : DateUtils.parseDate(
					fromDate, new String[] { getText("date.format") });
			Date t = StringUtils.isEmpty(toDate) ? null : DateUtils.parseDate(
					toDate, new String[] { getText("date.format") });
			List<Integer> weekends = weekendManager.getWeekend();
			List<Date> holidays = holidayManager.getHolidays(f,t);
			List<Field> fields = fieldManager.getList();
			
			GeneralReportBean reportMain = new GeneralReportBean();
			reportMain.setCategory(getText("report.form.table.header.sum"));
			reportMain.setField(WebConstants.SUM);
			
			reports.add(reportMain);
			
			for (fieldCount = 0; fieldCount < fields.size(); fieldCount++) {
				Field field = fields.get(fieldCount);
				if(departmentId.equals("0")){
					servletContext.setAttribute(WebConstants.SERVLET_CONTEXT_REPORT_DEPARTMENTNAME, null);
					generateReportBean(reportMain, field, f, t, weekends, holidays, categoryCount);
				}else{
					if(field.getDepartment().getId() == NumberUtils.toLong(departmentId)){
						servletContext.setAttribute(WebConstants.SERVLET_CONTEXT_REPORT_DEPARTMENTNAME, field.getDepartment().getName());
						
						generateReportBean(reportMain, field, f, t, weekends, holidays, categoryCount);	
					}
				}
			}
			
			servletContext.setAttribute(WebConstants.SERVLET_CONTEXT_REPORT, reports);
			servletContext.setAttribute(WebConstants.SERVLET_CONTEXT_FROMDATE, this.fromDate);
			servletContext.setAttribute(WebConstants.SERVLET_CONTEXT_TODATE, this.toDate);
			servletContext.setAttribute(WebConstants.SERVLET_CONTEXT_TOTAL_RECEIVED_INMONTH, String.valueOf(fileReceivedThisMonth));
			servletContext.setAttribute(WebConstants.SERVLET_CONTEXT_TOTAL_RECEIVED_FROM_LASTMONTH, String.valueOf(fileRemainLastMonth));
		}else{
			
			return SUCCESS;
		}
		
		Long endPoint = System.currentTimeMillis();
		log.debug("------------EXITING REPORT------------");
		log.debug("------------PROCESS TIME: "+(endPoint-startPoint));
		return SUCCESS;
	}
	
	private void generateReportBean(GeneralReportBean reportMain, Field field, Date f, Date t, List<Integer> weekends, List<Date> holidays,int categoryCount){

		GeneralReportBean reportByFieldObj = new GeneralReportBean();
		//reportObj.setField(field.getName());
		reportByFieldObj.setCategory(field.getDepartment().getName());
		reportByFieldObj.setField(WebConstants.DEP_NAME);
		
		reports.add(reportByFieldObj);
		
		Set<Category> categories = field.getCategories();
		for (Iterator<Category> iterator = categories.iterator(); iterator.hasNext();) {
			Category category = iterator.next();
			GeneralReportBean reportByCategory;
			List<File> files = new ArrayList<File>();
			
			//Updated by THOND.2012.04.18
			Set<SubCategory> lstSubCate = category.getSubCategories();
			if(lstSubCate.size()!=0){
				for (Iterator<SubCategory> iterator2 = lstSubCate.iterator(); iterator2.hasNext();) {
					SubCategory subCategory = (SubCategory) iterator2.next();
					files = fileManager.getFilesForReport(category.getId(),subCategory.getId(), f, t);
					
					reportByCategory = calculateFileOfCategory(category, files, f, t, weekends, holidays, reportByFieldObj);
					reportByCategory.setCategory(category.getCategoryName() + "(" + subCategory.getName() + ")");
					
					categoryCount++;
					reports.add(reportByCategory);
				}
			}else{
				// Update total files in month (include of approved and do not approve)
				files = fileManager.getFilesForReport(category.getId(),null, f, t);
				
				reportByCategory = calculateFileOfCategory(category, files, f, t, weekends, holidays, reportByFieldObj);
				reportByCategory.setCategory(category.getCategoryName());
				
				categoryCount++;
				reports.add(reportByCategory);
			}
			
		}
		reportMain.setTotalInMonth((NumberUtils.toInt(reportByFieldObj.getTotalInMonth()) + NumberUtils.toInt(reportMain.getTotalInMonth())) + "");
		
		reportMain.setResolvedInMonth(reportMain.getResolvedInMonth() + reportByFieldObj.getResolvedInMonth());
		
		reportMain.setResolvedOnTime(reportMain.getResolvedOnTime() + reportByFieldObj.getResolvedOnTime());
		
		reportMain.setTotalOverTime(reportMain.getTotalOverTime() + reportByFieldObj.getTotalOverTime());
		
		reportMain.setOverTimeLessThanFive(reportMain.getOverTimeLessThanFive() + reportByFieldObj.getOverTimeLessThanFive());
		
		reportMain.setOverTimeBetweenFiveAndTen(reportMain.getOverTimeBetweenFiveAndTen() + reportByFieldObj.getOverTimeBetweenFiveAndTen());
		
		reportMain.setOverTimeBetweenTenAndTwenty(reportMain.getOverTimeBetweenTenAndTwenty() + reportByFieldObj.getOverTimeBetweenTenAndTwenty());
		
		reportMain.setOverTimeMoreThanTwenty(reportMain.getOverTimeMoreThanTwenty() + reportByFieldObj.getOverTimeMoreThanTwenty());
		
		reportMain.setTotalNotApproved(reportMain.getTotalNotApproved() + reportByFieldObj.getTotalNotApproved());
		
		reportMain.setNotApprovedOverdue(reportMain.getNotApprovedOverdue() + reportByFieldObj.getNotApprovedOverdue());
		
		reportMain.setNotApprovedBeforeDeadline(reportMain.getNotApprovedBeforeDeadline() + reportByFieldObj.getNotApprovedBeforeDeadline());
		
	}

	private GeneralReportBean calculateFileOfCategory(Category category, List<File> files,
			Date f, Date t,
			List<Integer> weekends,
			List<Date> holidays,GeneralReportBean reportByFieldObj){
		
		GeneralReportBean resultObj = new GeneralReportBean();
		
		resultObj.setField(WebConstants.CATE_NAME);
		resultObj.setTotalInMonth(files.size()+"");
		
		int processTime = 0;
		
		for (File file : files) {
			Date receivedDate = file.getInputDate().toDate();
			Date approvedDate = null;
			processTime = getWorkingDays(file.getInputDate().toDate(), file.getOutputDate().toDate(),weekends,holidays);
			
			if(file.getDateCompleted()!=null) approvedDate = file.getDateCompleted().toDate();
			
			if(receivedDate.before(f)) fileRemainLastMonth++;
			if(receivedDate.after(f)) fileReceivedThisMonth++;
			
			if(checkApprovedFiles(file, f, t)){
//				totalApprovedFiles++;
				resultObj.increaseResolvedInMonth();
				
				//Update number of files that approved on time
				//Looking for number of holidays and weekends between START_DATE and END_DATE
				if(approvedDate!=null && receivedDate!=null){
					//REAL_TIME = (APPROVED_DATE - RECEIVED_DATE) - HOLIDAY - WEEKEND
					int realTime = getWorkingDays(receivedDate, approvedDate,weekends,holidays);
					 //Count file that processed on time
					 if(realTime <= processTime) resultObj.increaseResolvedOnTime();//totalApprovedOnTime++;
					 else{
						 //Count file that processed overtime
						//totalApprovedOverTime++;
						 resultObj.increaseTotalOverTime();
						 
						int overtime = realTime - processTime;
						if(overtime <= WebConstants.FIVE) resultObj.increaseOverTimeLessThanFive(); //overTimeLessThanFive++;
						else if(overtime > WebConstants.FIVE && overtime <=WebConstants.TEN) resultObj.increaseOverTimeBetweenFiveAndTen(); //overTimeBetweenFiveAndTen++;
						else if(overtime > WebConstants.TEN && overtime <=WebConstants.TWENTY) resultObj.increaseOverTimeBetweenTenAndTwenty(); //overTimeBetweenTenAndTwenty++;
						else if(overtime > WebConstants.TWENTY ) resultObj.increaseOverTimeMoreThanTwenty();//overTimeMoreThanTwenty++;
						
					 }
				}
				
			}else if(approvedDate == null){
				// Total files not approved
				//totalNotApproved ++;
				resultObj.increaseTotalNotApproved();
				int remainTime = getWorkingDays(receivedDate, t,weekends,holidays);
				// END_DATE � RECEIVED_DATE > PROCESS_DAY
				if(remainTime >= processTime) resultObj.increaseNotApprovedOverdue();//notApprovedOverdue++;
				else resultObj.increaseNotApprovedBeforeDeadline(); //notApprovedBeforeDeadline++;
			}
		}
		
		reportByFieldObj.setTotalInMonth((NumberUtils.toInt(reportByFieldObj.getTotalInMonth()) + files.size()) + "");
		
		reportByFieldObj.setResolvedInMonth(reportByFieldObj.getResolvedInMonth() + resultObj.getResolvedInMonth());
		
		reportByFieldObj.setResolvedOnTime(reportByFieldObj.getResolvedOnTime() + resultObj.getResolvedOnTime());
		
		reportByFieldObj.setTotalOverTime(reportByFieldObj.getTotalOverTime() + resultObj.getTotalOverTime());
		
		reportByFieldObj.setOverTimeLessThanFive(reportByFieldObj.getOverTimeLessThanFive() + resultObj.getOverTimeLessThanFive());
		
		reportByFieldObj.setOverTimeBetweenFiveAndTen(reportByFieldObj.getOverTimeBetweenFiveAndTen() + resultObj.getOverTimeBetweenFiveAndTen());
		
		reportByFieldObj.setOverTimeBetweenTenAndTwenty(reportByFieldObj.getOverTimeBetweenTenAndTwenty() + resultObj.getOverTimeBetweenTenAndTwenty());
		
		reportByFieldObj.setOverTimeMoreThanTwenty(reportByFieldObj.getOverTimeMoreThanTwenty() + resultObj.getOverTimeMoreThanTwenty());
		
		reportByFieldObj.setTotalNotApproved(reportByFieldObj.getTotalNotApproved() + resultObj.getTotalNotApproved());
		
		reportByFieldObj.setNotApprovedOverdue(reportByFieldObj.getNotApprovedOverdue() + resultObj.getNotApprovedOverdue());
		
		reportByFieldObj.setNotApprovedBeforeDeadline(reportByFieldObj.getNotApprovedBeforeDeadline() + resultObj.getNotApprovedBeforeDeadline());
		
		return resultObj;
	}

	/*
	 * Get files that processed by operator
	 */
	public String statisticsByUser() {
		Date t; 
		Date f; 
		try {
			f = StringUtils.isEmpty(fromDate) ? null : DateUtils.parseDate(
					fromDate, new String[] { getText("date.format") });
			t = StringUtils.isEmpty(toDate) ? null : DateUtils.parseDate(
					toDate, new String[] { getText("date.format") });
			
			if(this.userId!=null && !"".equals(this.userId)){
				User approver = userManager.get(Long.parseLong(this.userId));
				ExtendedPaginatedList paginatedList = paginateListFactory.getPaginatedListFromRequest(ServletActionContext.getRequest());
				this.resultFileByUser = fileManager.findFileByApprover(
						approver.getId(), f, t, null,
						WebConstants.TASKLIST_FILTER_TYPE_ALL, paginatedList);
			}
			
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return SUCCESS;
	}
	
	private String departmentName;
	
	private String replyMessage;
	
	private ExchangeManager exchangeMsgManager;
	
	private String fileId;

	private String approverId;
	
	
	
	/***
	 * Send alert message from current user to another user
	 * @return
	 */
	public String sendReplyMsg(){
		log.debug("Enter method sendReplyMsg");
		User currentUser = (User) ActionContext.getContext().getSession().get(WebConstants.USER_INFO);
		
		try {
			
			log.debug("FileId: " + fileId);
			log.debug("ApproverId: "+ approverId);
			if(this.fileId!=null && !"".equals(fileId) && this.approverId != null && !"".equals(approverId)){
				File currentFile = this.fileManager.get(fileId);
				
				if(currentFile!=null){
					Exchange reply = new Exchange();
					
					reply.setComment(this.getReplyMessage());
					reply.setDate(new DateTime());
					reply.setFile(currentFile);
					
					//Update sender
					reply.setSender(currentUser);
					
					//Update receiver
					User receiverMsg = this.userManager.get(Long.parseLong(this.approverId));
					reply.setUser(receiverMsg);
					
					//Set status to NEW
					reply.setStatus(false);
					
					this.exchangeMsgManager.save(reply);
				}
			}else{
				log.debug("FileId or ApproverId is Null");
			}
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
		return SUCCESS;
	}
	public String getListFileByDepartment(){
		
		log.debug("enter method getListFileByDepartment...");
		try {
			User user = (User) ActionContext.getContext().getSession().get(WebConstants.USER_INFO);
			if(user!=null){
				ExtendedPaginatedList paginatedList = paginateListFactory.getPaginatedListFromRequest(ServletActionContext.getRequest());
				this.lstFileByDepartment = this.fileManager.findFileByDeparment(user.getDepartment().getId(), "false", paginatedList);

				Department dept = this.departmentManager.get(user.getDepartment().getId());
				this.departmentName = dept.getName();
			}
			
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return SUCCESS;
	}
	
	List<DepartmentReportView> lstReportByDepartment;
	public List<DepartmentReportView> getLstReportByDepartment() {
		return lstReportByDepartment;
	}


	public void setLstReportByDepartment(
			List<DepartmentReportView> lstReportByDepartment) {
		this.lstReportByDepartment = lstReportByDepartment;
	}


	/***
	 * 
	 * @return
	 */
	public String statisticsByDepartment() {
		Date t; 
		Date f; 
		lstReportByDepartment = new ArrayList<DepartmentReportView>();
		try {
			f = StringUtils.isEmpty(fromDate) ? null : DateUtils.parseDate(
					fromDate, new String[] { getText("date.format") });
			t = StringUtils.isEmpty(toDate) ? null : DateUtils.parseDate(
					toDate, new String[] { getText("date.format") });
			
			if(this.groupId!=null && !"".equals(this.groupId)){

				Department dept = this.departmentManager.get(Long.parseLong(this.groupId));
				for (Iterator iterator = dept.getUsers().iterator(); iterator.hasNext();) {
					User user = (User) iterator.next();
					DepartmentReportView report = new DepartmentReportView();
					report.setFullname(user.getFullname());
					report.setTotalFile(this.fileManager.getTotalRecordByFilterCondition(user.getId(), f, t, "", WebConstants.TASKLIST_FILTER_TYPE_ALL)+"");
					report.setTotalOvertime(this.fileManager.getTotalRecordByFilterCondition(user.getId(), f, t, "", WebConstants.TASKLIST_FILTER_TYPE_OVERDEADLINE)+"");
					
					lstReportByDepartment.add(report);
				}
			}
			
		} catch (ParseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return SUCCESS;
	}
	
	
	

	@Override
	public void validate() {
		log.debug("GO TO VALIDATE...");
		if(this.fromDate!=null && !"".equals(this.fromDate) && this.toDate!=null && !"".equals(this.toDate)){
			try {
				Date f = StringUtils.isEmpty(fromDate) ? null : DateUtils.parseDate(
						fromDate, new String[] { getText("date.format") });
				Date t = StringUtils.isEmpty(toDate) ? null : DateUtils.parseDate(
						toDate, new String[] { getText("date.format") });
				
				if(t.before(f)) addActionError(getText("statistic.fromDate.compareTo.toDate"));
			} catch (ParseException e) {
				
				e.printStackTrace();
			}
		}else{
			if(this.fromDate==null || "".equals(this.fromDate)) addActionError(getText("statistic.form.fromdate"));
			if(this.toDate==null || "".equals(this.toDate)) addActionError(getText("statistic.form.todate"));
		}
	}


	public void setLstFileByDepartment(ExtendedPaginatedList lstFileByDepartment) {
		this.lstFileByDepartment = lstFileByDepartment;
	}


	public ExtendedPaginatedList getLstFileByDepartment() {
		return lstFileByDepartment;
	}


	public void setDepartmentName(String departmentName) {
		this.departmentName = departmentName;
	}


	public String getDepartmentName() {
		return departmentName;
	}


	public void setReplyMessage(String replyMessage) {
		this.replyMessage = replyMessage;
	}


	public String getReplyMessage() {
		return replyMessage;
	}

	@Autowired
	public void setExchangeMsgManager(ExchangeManager exchangeMsgManager) {
		this.exchangeMsgManager = exchangeMsgManager;
	}


	public ExchangeManager getExchangeMsgManager() {
		return exchangeMsgManager;
	}


	public void setFileId(String fileId) {
		this.fileId = fileId;
	}


	public String getFileId() {
		return fileId;
	}


	public void setApproverId(String approverId) {
		this.approverId = approverId;
	}


	public String getApproverId() {
		return approverId;
	}
	
}
